package com.imgpro.service.Impl;

import com.github.xiaoymin.knife4j.core.util.StrUtil;
import com.google.gson.Gson;
import com.imgpro.Constant.JwtClaimsConstant;
import com.imgpro.Constant.MessageConstant;
import com.imgpro.Constant.StatusConstant;
import com.imgpro.Exception.PasswordErrorException;
import com.imgpro.Exception.SignUpFailedException;
import com.imgpro.Exception.UpdateFailedException;
import com.imgpro.Properties.JwtProperties;
import com.imgpro.Utils.JwtUtil;
import com.imgpro.constants.RedisConstant;
import com.imgpro.dto.UserDTO;
import com.imgpro.dto.UserLoginDTO;
import com.imgpro.dto.UserSingUpDTO;
import com.imgpro.entity.User;
import com.imgpro.mapper.UserMapper;
import com.imgpro.service.UserService;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import javax.security.auth.login.AccountLockedException;
import javax.security.auth.login.AccountNotFoundException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private UserService userService;

    @Override
    public User login(UserLoginDTO userLoginDTO) throws Exception {
        String username = userLoginDTO.getUsername();
        String password = userLoginDTO.getPassword();

        //1、根据用户名查询数据库中的数据
        User user = userMapper.getByUsername(username);

        //2、处理各种异常情况（用户名不存在、密码不对、账号被锁定）
        if (user == null) {
            //账号不存在
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }

        //密码比对
        password = DigestUtils.md5DigestAsHex(password.getBytes());

        if (!password.equals(user.getPasswordHash())) {
            //密码错误
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }

        if (user.getStatus() == StatusConstant.DISABLE) {
            //账号被锁定
            throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
        }

        //3、返回实体对象
        return user;
    }

    /**
     * 用户注册方法
     *
     * 该方法用于处理用户注册请求，首先检查用户名和邮箱是否已存在于系统中
     * 如果已存在，抛出异常提示用户信息重复；如果不存在，将用户信息保存到数据库中
     *
     * @param userSingUpDTO 用户注册信息，包含用户名、密码和邮箱等字段
     * @return 如果注册成功，返回新创建的用户对象
     * @throws Exception 如果用户名或邮箱已存在，抛出异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public User signUp(UserSingUpDTO userSingUpDTO) throws Exception {
        // 检查用户名是否已存在
        if(userMapper.getByUsername(userSingUpDTO.getUsername()) != null){
            throw new SignUpFailedException(MessageConstant.USER_NAME_DUP);
        }
        // 检查邮箱是否已存在
        if(userMapper.getByEmail(userSingUpDTO.getEmail())!=null){
            throw new SignUpFailedException(MessageConstant.USER_EMAIL_DUP);
        }

        User user = new User();
        BeanUtils.copyProperties(userSingUpDTO, user);
//        将密码设置为密文
        user.setPasswordHash(DigestUtils.md5DigestAsHex(userSingUpDTO.getPassword().getBytes()));
        user.setUuid(String.valueOf(UUID.randomUUID()));
        userMapper.insert(user);

        return user;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDTO showUser(String token){
        Gson gson = new Gson();
        UserDTO userDTO = new UserDTO();

        if(token == null){
            return userDTO;
        }

//        Object jwtProperties;
        Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
        String userId = claims.get(JwtClaimsConstant.USER_ID).toString();


        if(StrUtil.isBlank(userId)){
            log.info("StrUtil.isBlank");
//            response.setStatus(401);
            return userDTO;
        }
//        以token创建redis查询的key
        String key = RedisConstant.LOGIN_TOKEN_KEY + userId;


        HashOperations<String, Object, Object> opsForHash = stringRedisTemplate.opsForHash();
//         查询redis中存储的token信息,作为cache
        Map<Object, Object> userMap = opsForHash.entries(key);

        if(!userMap.isEmpty()){
            log.info("从Redis里面的用户缓存查到了数据，直接一个返回");
            String json = gson.toJson(userMap);
            userDTO = gson.fromJson(json , UserDTO.class);
            return userDTO;
        }

//        如果从redis里面没有查询到，则查询数据库
        log.info("从redis里面没有查询到，则查询数据库");
        User user = userMapper.getByUuid(userId);

        if(user == null){
            log.info("没有查询到用户，数据库中没有用户");
//            response.setStatus(401);
            return userDTO;
        }

        BeanUtils.copyProperties(user, userDTO);

//        将userDTO转化为map
        Map<String, String> stringMap = new HashMap<>();
        Map<String, Object> userMapDTO = gson.fromJson(gson.toJson(userDTO), Map.class);

        for (Map.Entry<String, Object> entry : userMapDTO.entrySet()) {
            stringMap.put(entry.getKey(), String.valueOf(entry.getValue()));
        }

        opsForHash.putAll(key, stringMap);

        return userDTO;


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateUser(String token, UserDTO userDTO) {


        log.info("当前用户的token是这样的++++{}",token);

        if(token == null){
            throw new UpdateFailedException("更新失败，请登录后重试");
        }

        String userId = null;
        try {
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
            userId = claims.get(JwtClaimsConstant.USER_ID).toString();
        } catch (Exception e) {
            throw new UpdateFailedException("更新失败，请登录后重试");
        }


        if(StrUtil.isBlank(userId)){
            log.info("StrUtil.isBlank——token里面竟然没有token");
//            response.setStatus(401);
            throw new UpdateFailedException("更新失败，请登录后重试");
        }

//        判断邮箱和用户名能不能重复
        if(userMapper.getByUsernameOther(userDTO.getUsername(), userId) != null ){
            throw new UpdateFailedException(MessageConstant.USER_NAME_DUP);
        }
        // 检查邮箱是否已存在
        if(userMapper.getByEmailOther(userDTO.getEmail(), userId)!=null){
            throw new UpdateFailedException(MessageConstant.USER_EMAIL_DUP);
        }



        //        以token创建redis查询的key
        User user = new User();

        BeanUtils.copyProperties(userDTO, user);
        user.setUuid(userId);

        userMapper.updateUser(user);
        log.info("数据库已经完成了更新，相当于现在只需要删掉redis缓存");

        String key = RedisConstant.LOGIN_TOKEN_KEY + userId;
        stringRedisTemplate.delete(key);
        log.info("Redis中已经删掉了内容，鉴定为好起来");

    }

}
